/*
 * Element.h
 *
 *  Created on: Jan 16, 2013
 *      Author: lordmzn
 */

#ifndef MOLEM_ELEMENT_H_
#define MOLEM_ELEMENT_H_

namespace MOLEM {

static const double ELEMENT_Z_DEFAULT_VALUE = -2.0;
static const double ELEMENT_Z_BORDER_VALUE = -2.0;

namespace Direction {
enum DirEnum {
	NONE = 0,
	NORTH = 1, 		// up, 			(nr--, nc)
	NORTH_EAST = 2,	// up-right,	(nr--, nc++)
	EAST = 3,		// right,		(nr, nc++)
	SOUTH_EAST = 4,	// down-right,	(nr++, nc++)
	SOUTH = 5,		// down,		(nr++, nc)
	SOUTH_WEST = 6,	// down-left,	(nr++, nc--)
	WEST = 7,		// left,		(nr, nc--)
	NORTH_WEST = 8	// up-left,		(nr--, nc--)
};
static const unsigned int NUMBER_OF_DIRECTION = 8;
static const DirEnum allDirections[NUMBER_OF_DIRECTION] = { NORTH, NORTH_EAST,
		EAST, SOUTH_EAST, SOUTH, SOUTH_WEST, WEST, NORTH_WEST };
}

/**
 * Elements of a surface
 */
class Element {
public:
	/**
	 * Void initializer should initialize z at DATA_DEFAULT_VALUE
	 */
	Element(unsigned int xx, unsigned int yy);
	Element(unsigned int xx, unsigned int yy, Direction::DirEnum boundary);
	Element(const Element&);
	virtual ~Element();

	bool operator==(const Element&) const;
	bool operator!=(const Element&) const;

	virtual void setZvalue(double);
	double getZvalue() const;
	double getCartesianDistance(const Element&) const;
	/**
	 * When initialized, this element is disconnected, must be connected
	 * before use. If it's a border element, this element should be passed
	 * instead of the missing neighbors.
	 */
	bool connect(Element& west, Element& north, Element& east, Element& south);
	bool isConnected() const;
	/**
	 * @Deprecated?
	 * Retrieve the cell object next to the one passed as argument
	 * in the direction chosen, or returns the argument if the
	 * direction is outside the border
	 */
	Element& getNeighbour(Direction::DirEnum);

private:
	/**
	 * Contains the value of the data over this element
	 * of surface.
	 */
	double z;
	/**
	 * Contains coordinates to the point
	 */
	const unsigned int x;
	const unsigned int y;
	/**
	 * Contain pointers to neighbor elements. If one of them is
	 * null it means that that direction leads outside the surface.
	 */
	Element* west_el;
	Element* north_el;
	Element* east_el;
	Element* south_el;
	/**
	 * true if it's on the boundary of the domain
	 */
	const Direction::DirEnum boundary;
};

} /* namespace MOLEM */
#endif /* MOLEM_ELEMENT_H_ */
